#include "Shader.hpp"

using namespace std;

Shader::Shader( std::string vertexShader, std::string fragmentShader )
{
	vertex = ShaderLibrary::getVertexShader( vertexShader );
	fragment = ShaderLibrary::getFragmentShader( fragmentShader );

	m_programId = glCreateProgram();
	assert( glGetError() == GL_NO_ERROR);
	
	
	glAttachShader( m_programId, vertex->m_id );
	assert( glGetError() == GL_NO_ERROR);
	glAttachShader( m_programId, fragment->m_id );

	GLuint err = glGetError();
	if( err != GL_NO_ERROR )
        Logger::write( "Shader", "Shader( string, string ) @ 1", (const char*)gluErrorString( err ), Logger::Error );

	assert( glGetError() == GL_NO_ERROR);
	
	
	glLinkProgram( m_programId );
	assert( glGetError() == GL_NO_ERROR);
	

	
    glUseProgram( (GLuint)NULL );
	
	GLint ret;
	GLint len;
	GLchar buffer[1024];
	glGetShaderiv( vertex->m_id, GL_COMPILE_STATUS, &ret );
	assert( glGetError() == GL_NO_ERROR);
	if( ret == GL_FALSE )
    {
        glGetShaderInfoLog( vertex->m_id, 1024, &len, buffer );
        Logger::write( "Shader", "Shader( string, string ) @ 2",
                       QString( "Shader did not compile: " ) + buffer, Logger::Error );
		assert(0);
		
	}
	
	
	glGetShaderiv( fragment->m_id, GL_COMPILE_STATUS, &ret );
	assert( glGetError() == GL_NO_ERROR);
	if( ret == GL_FALSE )
	{
        glGetShaderInfoLog( fragment->m_id, 1024, &len, buffer );
        Logger::write( "Shader", "Shader( string, string ) @ 2",
                       QString( "Fragment shader did not compile: " ) + buffer, Logger::Error );
	}

	


	

	
	glGetProgramiv( m_programId, GL_LINK_STATUS, &ret );
	assert( glGetError() == GL_NO_ERROR );
	if( ret == GL_FALSE )
	{
		int logLen = 0;
		glGetProgramiv( m_programId, GL_INFO_LOG_LENGTH, &len);
		glGetProgramInfoLog( m_programId, len, &logLen, buffer);

        Logger::write( "Shader", "Shader( string, string ) @ 2",
                       QString( "Fragment shader did not link: " ) + buffer, Logger::Error );
	}
	
	assert( glGetError() == GL_NO_ERROR );	
}


void Shader::bind()
{
	glUseProgram( m_programId );

	assert( glGetError() == GL_NO_ERROR);
	
	GLint texture = glGetUniformLocation( m_programId, "baseTexture" );
	if( texture != -1 )
	{
		glUniform1i( texture, 0 );
	}

	assert( glGetError() == GL_NO_ERROR);
	
	GLint gloss = glGetUniformLocation( m_programId, "glossTexture" );
	if( gloss != -1 )
	{
		glUniform1i( gloss, 1 );
	}

	assert( glGetError() == GL_NO_ERROR);	
	
	GLint shadow = glGetUniformLocation( m_programId, "myShadowMap" );
	if( shadow != -1 )
	{
		glUniform1i( shadow, 2 );
	}	
	
	assert( glGetError() == GL_NO_ERROR);
}

void Shader::unbind()
{
	GLuint err = glGetError();
	if( err != GL_NO_ERROR )
	{
        Logger::write( "Shader", "unbind() @ 1", (const char*)gluErrorString(err ), Logger::Error );
		assert( glGetError() == GL_NO_ERROR);
	}

	
    glUseProgram( (GLuint)NULL );
	
	err = glGetError();
	if( err != GL_NO_ERROR )
	{
        Logger::write( "Shader", "unbind() @ 2", (const char*)gluErrorString(err ), Logger::Error );
		assert( glGetError() == GL_NO_ERROR);
	}	
}

GLuint Shader::getUniformLocation( std::string name )
{
	return glGetUniformLocation( m_programId, name.c_str() );
}


